#ifndef _VECTOR_3D_H_
#define _VECTOR_3D_H_

#include "./geometry_define.h"
#include "./cartesian_coordinate.h"

namespace Mathematics {
	namespace Geometry {

		//using namespace Matrix;

		//! Class for manipulating 3D vectors.
		/*!
			Spatial uses of vector, like scalar product and operations.
		*/
		class Vector3D: public Wtb {
		private:
			
			/*! Spatial dimension. */
			static const usint spt_dim = 3;
			/*! Pointer for the dimension values. */
			double *coord;
			/*! Maximum module. Set this positive for having limited vector. */
			double max_mod;
			
			void copy(const Vector3D &original);
			bool create();
			void free();
			void verifyMod();
			
		public:
			
				// -constructors-
			/*! 
				Constructor
				
				\param x X dimension.
				\param y Y dimension.
				\param z Z dimension.
				\param max maximum module.
				\code
				Vector3D vet(3.0,4.0);	// creates a Vector3D with coordinates (3,4,0) and max module -1.0 (ilimited).
				Vector3D vet(3.0,-3.0,4.0,1.0); // Vector3D (3.0,-3.0,4.0) and max module 1.0 (wich will adjuste the Vector3D to unitary )
				\endcode
			*/
			Vector3D( const double &x = 0.0, const double &y = 0.0, const double &z = 0.0, const double &max = -1.0 );
			/*! 
				Copy Constructor
				
				\param original The object to be copied.
				\sa Vector3D::Vector3D( const double &x, const double &y, const double &z, const double &max );
				
				\code
				Vector3D vet(5.0,-2.0);	// creates a vector (5.0,-2.0).
				// ...
				Vector3D copy( vet );	// creates a new Vector3D with the same dimension values.
				\endcode
			*/
			Vector3D(const Vector3D &original);
			/*! 
				Destructor
			*/
			~Vector3D();
			
				// -getters & setters-
			/*! 
				Method for getting dimension values in the Vector3D.
				Can throw OutOfBoundsException if the parameter is invalid.
				
				\param index Index of the desired value.
				\return copy of the desired value.
				\sa void Vector3D::setValue(const usint &index, const double &item)
				\sa double& operator[](const usint &index)const
				\sa class OutOfBoundsException
				
				\code
				Vector3D vet(1.0,1.0);
				cout << vet.getValue(0) << endl; // prints 1.0
				vet.setValue(0, 5.0);
				cout << vet.getValue(0) << endl; // prints 5.0
				\endcode
			*/
			inline double getCoord(const usint &index) const {
				if( index >= spt_dim ){
					throw OutOfBoundsException("Acesso Invalido.",spt_dim,index);
				}
				return coord[index];
			};
			/*! 
				Method for changing values in the Vector3D
				Can throw OutOfBoundsException if the parameter is invalid.
				Warning: if the Vector3D is bounded setting coordinates individually
					can have unnexpected outcome.
				
				\param index Index of the desired position.
				\param item The desired new value.
				\sa double Vector3D::getValue(const usint &index)const
				\sa double& Vector3D::operator[](const usint &index)const
				\sa class OutOfBoundsException
				
				\code
				Vector3D vet(5);
				vet.setValue(0, 5.0);
				cout << vet.getValue(0) << endl; // prints 5.0
				\endcode
			*/
			inline void setCoord(const usint &index, const double &item){
				if(index >= spt_dim){
					throw OutOfBoundsException("Acesso Invalido.",spt_dim,index);
				}
				coord[index] = item;
				verifyMod();
			};
			
			//! getter for max_mod
			inline double getMaxMod() const {
				return max_mod;
			};
			//! setter for max_mod
			inline void setMaxMod( const double &value ){
				max_mod = value;
				verifyMod();
			};
			
			/*! 
				Changes the current module of the vector.
				
				\code
				Vector3D vet(3.0, 4.0, 0.0);
				vet.setMod(1.0);
				cout << vet << endl; // prints ( 0.6, 0.8 , 0.0 )
				\endcode
			*/
			void setMod( const double &value ) ;
			/*! 
				The module of the vector.
				
				\return the vector's module.
				\code
				Vector3D vet(3.0, 4.0, 0.0);
				cout << vet.mod() << endl; // prints 5.0
				\endcode
			*/
			double mod() const ;
			/*! 
				The unitary vector.
				
				\return the versor in a new Vector3D.
				\code
				Vector3D vet(3.0, 4.0, 0.0);
				cout << vet.versor() << endl; // prints ( 0.6, 0.8 , 0.0 )
				\endcode
			*/
			Vector3D versor() const ;
			
			/*! 
				Projecting one vector in another one (alongside).
				
				\param vet The vector to project this on.
				\return the projection in a new Vector3D.
				\code
				Vector3D vet(3.0, 4.0, 0.0);
				cout << vet.projectedOn( uX ) << endl; // prints ( 3.0, 0.0 , 0.0 )
				cout << vet.projectedOn( uY ) << endl; // prints ( 0.0, 4.0 , 0.0 )
				\endcode
			*/
			Vector3D projectedOn( const Vector3D &vet ) const ;
			/*! 
				Reflecting one vector in another one (through).
				
				\param vet The vector to reflect this on.
				\return the reflection in a new Vector3D.
				\code
				Vector3D vet(3.0, 4.0, 0.0);
				cout << vet.reflectedOn( uX ) << endl; // prints ( -3.0, 4.0 , 0.0 )
				cout << vet.reflectedOn( uY ) << endl; // prints ( 3.0, -4.0 , 0.0 )
				\endcode
			*/
			Vector3D reflectedOn( const Vector3D &vet ) const ;

			//Vector3D zRotated( const double &degree ) const ;

			/*! 
				Verification if two vectors are LD.
				
				\param vet The vector to compare with this.
				\return boolean telling if they are colinear.
				\code
				Vector3D vet(3.0, 4.0, 0.0);
				Vector3D vet2(6.0, 8.0, 0.0);
				cout << vet.isColinear( vet2 ) << endl; // true
				cout << vet.isColinear( uY ) << endl; // false
				\endcode
			*/
			inline bool isColinear( const Vector3D &vet ) const {
				return ( (*this) % vet ).mod() == 0.0;
			};
			
			/*! 
				Vector3D attribution
				
				\param vet Vector3D desired to attribution.
				
				\code
				Vector3D copy, alias, vet(1.0,2.0,3.0);
				alias = copy = vet; // alias and copy have now the value (1.0,2.0,3.0)
				\endcode
			*/
			Vector3D& operator = (const Vector3D &vet);
			/*! 
				Vector3D sum
				
				\param vet Vector3D desired to sum.
				\sa Vector3D::operator+=(const Vector3D &vet)
				
				\code
				Vector3D vet(1.0,2.0,3.0);
				cout << vet + vet << endl; // prints ( 2.0, 4.0, 6.0 )
				\endcode
			*/
			Vector3D operator + (const Vector3D &vet) const;
			/*! 
				Vector3D sum with left attribution
				
				\param vet Vector3D desired to sum.
				\sa Vector3D::operator=(const Vector3D &vet)
				\sa Vector3D::operator+(const Vector3D &vet)const
				
				\code
				Vector3D atr(1.0,-2.0,1.2), vet(1.0,2.0,3.0);
				atr += vet; // atr has now the value (2.0,0.0,4.2)
				\endcode
			*/
			Vector3D& operator += (const Vector3D &vet);
			/*! 
				Vector3D subtraction
				
				\param vet Vector3D desired to subtract.
				\sa Vector3D::operator-=(const Vector3D &vet)
				
				\code
				Vector3D vet(1.0,2.0,3.0);
				cout << vet - vet << endl; // prints ( 0.0, 0.0, 0.0 ), pretty dumb!
				\endcode
			*/
			Vector3D operator - (const Vector3D &vet) const;
			/*! 
				Vector3D subtraction with left attribution
				
				\param vet Vector3D desired to subtract.
				\sa Vector3D::operator=(const Vector3D &vet)
				\sa Vector3D::operator-(const Vector3D &vet)const
				
				\code
				Vector3D atr(1.0,-2.0,1.2), vet(1.0,2.0,3.0);
				atr -= vet; // atr has now the value ( 0.0, -4.0, -1.8 )
				\endcode
			*/
			Vector3D& operator -= (const Vector3D &vet);
			/*! 
				Vector3D vectorial product
				
				\param vet Vector3D desired to make vectorial product with the Vector3D.
				\sa Vector3D::operator%=(const Vector3D &vet)
				
				\code
				using namespace OrthonormalBase;
				cout << uX ^ uY << endl; // prints ( 0.0, 0.0, 1.0 ) wich is uZ
				\endcode
			*/
			Vector3D operator % (const Vector3D &vet) const;
			/*! 
				Vector3D vectorial product with left attribution
				
				\param vet Vector3D desired to make vectorial product with the Vector3D.
				\sa Vector3D::operator=(const Vector3D &vet)
				\sa Vector3D::operator%(const Vector3D &vet)
				
				\code
				Vector3D vet(1.0,0.0,-1.0);
				using namespace OrthonormalBase;
				vet %= uY; // vet has now the value ( -1.0, 0.0, 1.0 )
				\endcode
			*/
			Vector3D& operator %= (const Vector3D &vet);
			/*! 
				Vector3D scalar product
				
				\param vet Vector3D desired to make scalar product with the Vector3D.
				\sa Vector3D::operator^(const Vector3D &vet)
				
				\code
				Vector3D vet(1.0,2.0,3.0);
				cout << vet * 5 << endl; // prints ( 5.0, 10.0, 15.0 )
				\endcode
			*/
			double operator * (const Vector3D &vet) const;
			/*! 
				Vector3D multiplication by number
				
				\param scalar number desired to multiply the Vector3D.
				\sa Vector3D::operator*=(const double &scalar)
				
				\code
				Vector3D vet(1.0,2.0,3.0);
				cout << vet * 5 << endl; // prints ( 5.0, 10.0, 15.0 )
				\endcode
			*/
			Vector3D operator * (const double &scalar) const;
			/*! 
				Vector3D multiplication by number - comutative
				
				\param scalar number desired to multiply the Vector3D.
				\param vet the Vector3D.
				\sa Vector3D::operator*(const double &scalar)
				
				\code
				Vector3D vet(1.0,2.0,3.0);
				cout << 5 * vet << endl; // prints ( 5.0, 10.0, 15.0 )
				\endcode
			*/
			friend inline Vector3D operator * (const double &scalar, const Vector3D &vet){
				return vet*scalar;
			};
			/*! 
				Vector3D multiplication by number with left attribution
				
				\param scalar number desired to multiply the Vector3D.
				\sa Vector3D::operator=(const Vector3D &vet)
				\sa Vector3D::operator*(const double &scalar)const
				
				\code
				Vector3D vet(1.0,2.0,3.0);
				vet *= 3; // vet has now the value ( 3.0, 6.0, 9.0 )
				\endcode
			*/
			Vector3D& operator *= (const double &scalar);
			/*! 
				Vector3D division by number
				Can throw DivisionByZeroException.
				
				\param scalar number desired to divide the Vector3D. If zero Throws DivisionByZeroException.
				\sa Vector3D::operator/=(const double &scalar)
				\sa class DivisionByZeroException
				
				\code
				Vector3D vet(1.0,2.0,3.0);
				cout << vet / 5 << endl; // prints [ 0.2 0.4 0.6 ]
				\endcode
			*/
			Vector3D operator / (const double &scalar) const;
			/*! 
				Vector3D division by number with left attribution.
				Can throw DivisionByZeroException.
				
				\param scalar number desired to divide the Vector3D. If zero Throws DivisionByZeroException.
				\sa Vector3D::operator=(const Vector3D &vet)
				\sa Vector3D::operator/(const double &scalar)const
				\sa class DivisionByZeroException
				
				\code
				Vector3D vet(1.5,3.0,9.3);
				atr /= 3.0; // vet has now the value ( 0.5, 1.0, 3.1 )
				\endcode
			*/
			Vector3D& operator /= (const double &scalar);
			/*! 
				Vector3D comparison.
				
				\param vet Vector to compare with this one.
				\return boolean saying if all the coordinates are equal.
				\sa bool Vector3D::operator!=(const Vector3D &vet)const
				
				\code
				Vector3D vet(1.5,3.0,9.3);
				cout << ( vet == vet ) << endl; // true
				\endcode
			*/
			bool operator == (const Vector3D &vet) const ;
			/*! 
				Vector3D comparison.
				
				\param vet Vector to compare with this one.
				\return boolean saying the opposite of ==.
				\sa bool Vector3D::operator==(const Vector3D &vet)const
				
				\code
				Vector3D vet(1.5,3.0,9.3);
				cout << ( vet != vet ) << endl; // false
				\endcode
			*/
			inline bool operator != (const Vector3D &vet) const {
				return ! ( (*this) == vet );
			};
			/*! 
				Operator for accessing individual dimensions in the Vector3D
				
				\param index position to be accessed in the Vector3D.
				\return the value in that position.
				
				\code
				Vector3D vet(1.0,2.0,3.0);
				cout << vet[1] << endl;		// prints 2.0
				\endcode
			*/
			double& operator [] (const usint &index) const ;
			/*! 
				Operator for accessing individual dimensions in the Vector3D,
				using cartesian coordinates nomenclature.
				
				\param index position to be accessed in the Vector3D.
				\return the value in that position.
				\sa CartesianCoordinate
				
				\code
				Vector3D vet(1.0,2.0,3.0);
				cout << vet[X] << endl;		// prints 1.0
				cout << vet[Y] << endl;		// prints 2.0
				cout << vet[Z] << endl;		// prints 3.0
				\endcode
			*/
			double& operator [] (const CartesianCoordinate &index) const ;
			/*! 
				Operator for converting the Vector3D to a Matrix1D with 4 values (W = 1.0)
				
				\return a new Matrix1D with the information in this.
				\sa Matrix1D
				
				\code
				Vector3D vet1(1.0,2.0,3.0);
				cout << "Vet1 : " << (Matrix::Matrix1D) vet1 << endl; // conversion
				cout << "Vet1 : " << (Matrix::Matrix2D) vet1 << endl; // conversion
				\endcode
			*/
			operator Matrix::Matrix1D () const;
			/*!
				Operator for multiplication of Matrix2D (4x4) and Vector3D (automaticaly does type conversion)
				\code
				Matrix2D mat(4,4);
				mat,
					1.0, 0.0, 0.0, 0.0, nl,
					0.0, 1.0, 0.0, 0.0, nl,
					0.0, 0.0, 1.0, 0.0, nl,
					0.0, 0.0, 0.0, 1.0;		// identity matrix
				Vector3D vet1(1.0,2.0,3.0);
				cout << "Vet1 : " << mat * vet1 << endl; // conversion
				\endcode
			*/
			friend Vector3D operator * ( const Matrix::Matrix2D &mat, const Vector3D &vet );
			/*! 
			*/
			double* toPointer() const ;
			/*! 
			*/
			float* toPointerf() const ;
			/*! 
				Method for converting the Vector3D in a string representation
				
				\return a string that represents the Vector3D.
				
				\code
				Vector3D vet(1.0,2.0,3.0);
				cout << vet.toS() << endl;		// prints ( 1.0, 2.0, 3.0 )
				\endcode
			*/
			virtual string toS() const ;
			/*! 
				Writes the value of the Vector3D in an opened file.
				
				\param parq Pointer to the opened file.
				\return boolean indicating failure or success of the operation
				
				\sa string Vector3D::toS()const
				
				\code
				Vector3D vet(1.0,2.0,3.0);
				vet.filePrint();		// prints ( 1.0, 2.0, 3.0 ) on the terminal
				\endcode
			*/
			virtual bool filePrint( FILE *parq = stdin ) const ;
			
			/*! 
				Method for Debug
				
				\code
				Vector3D::test();
				\endcode
			*/
			static void test();
			
		};
		
		//! Namespace containing the base unitary vectors
		/*!
			The basic vectors
		*/
		namespace OrthonormalBase {
			/*! i */
			extern const Vector3D uX;
			/*! j */
			extern const Vector3D uY;
			/*! k */
			extern const Vector3D uZ;
		};
	};
};

#endif // _VECTOR_3D_H_
